package com.nan.bytecode;

import com.nan.bytecode.asm.AOPImprove;
import com.nan.bytecode.asm.AOPTrack;
import com.nan.bytecode.asm.ASMCalc;
import com.nan.bytecode.asm.ASMHelloWorld;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestClient {
    public static void main(String[] var0) {
//        testHelloWorld();
//        testCalc();
//        testQueryUser();
        testTrack();
    }


    private static void testHelloWorld() {
        byte[] bytes = ASMHelloWorld.generate();
        outputClazz(bytes, "com/nan/bytecode/asm/HelloWorld.class");
        try {
            Class<?> clazz = Class.forName("com.nan.bytecode.asm.HelloWorld");
            Method main = clazz.getMethod("main", String[].class);
            main.invoke(null, (Object) null);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static void testCalc() {
        byte[] bytes = ASMCalc.generate();
        outputClazz(bytes, "com/nan/bytecode/asm/Calc.class");
        try {
            Class<?> clazz = Class.forName("com.nan.bytecode.asm.Calc");
            Object obj = clazz.newInstance();
            Method add = clazz.getMethod("add", int.class, int.class);
            int result = (int) add.invoke(obj, 10, 22);
            System.out.println("result=" + result);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    private static void testQueryUser() {
        try {
            byte[] bytes = AOPImprove.addProfiling();
            outputClazz(bytes, "com/nan/bytecode/asm/UserModel.class");
            MyClassLoader myClassLoader = new MyClassLoader();
            Class<?> clazz = myClassLoader.getClassByBytes(bytes);
            Object obj = clazz.newInstance();
            Method queryUserInfo = clazz.getMethod("queryUserInfo", String.class);
            String result = (String) queryUserInfo.invoke(obj, "122");
            System.out.println("result=" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void testTrack() {
        try {
            byte[] bytes = AOPTrack.track();
            outputClazz(bytes, "com/nan/bytecode/asm/UserModel.class");
            MyClassLoader myClassLoader = new MyClassLoader();
            Class<?> clazz = myClassLoader.getClassByBytes(bytes);
            Object obj = clazz.newInstance();
            Method queryUserInfo = clazz.getMethod("queryUserInfo", String.class);
            String result = (String) queryUserInfo.invoke(obj, "123");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class MyClassLoader extends ClassLoader {
        public Class getClassByBytes(byte[] bytes) {
            return defineClass(null, bytes, 0, bytes.length);
        }
    }

    private static void outputClazz(byte[] bytes, String name) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("/home/nan/AndroidStudioProjects/BytecodeProject/app/build/intermediates/javac/debug/classes/" + name);
            fos.write(bytes);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
